package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.util.StringValueResolver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Name AbstractBeanFactory
 * @Description: Bean 容器 [抽象] 类
 * 描述信息：该抽象类作为 BeanFactory 和 SingletonBeanRegistry 的实现类，具备二者的能力。
 * BeanFactory：定义获取 Bean 实例的接口。
 * SingletonBeanRegistry：定义获取单例 Bean 实例的方法。
 * 扩展：增加了创建 Bean 实例、获取 BeanDefinition 信息的接口。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-03-14 14:44:02
 **/
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
    private final Map<String, Object> factoryBeanCache = new HashMap<>();
    private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();
    private ConversionService conversionService;

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T) getBean(name);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        Object shareInstance = getSingleton(name);
        if (shareInstance != null) {
            // 判断当前 Bean 实例是否为 FactoryBean? 如果是, 则从 FactoryBean#getObject 中创建加工 Bean。
            return getObjectFromBeanInstance(shareInstance, name);
        }
        BeanDefinition beanDefinition = getBeanDefinition(name);
        Object bean = createBean(name, beanDefinition);
        return getObjectFromBeanInstance(bean, name);
    }

    /**
     * 判断当前 Bean 实例是否为 FactoryBean? 如果是, 则从 FactoryBean#getObject 中创建加工 Bean。
     *
     * @param bean 原 Bean 实例
     * @param name 原 Bean 名称
     * @return java.lang.Object 结果
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-20 17:26:02
     */
    protected Object getObjectFromBeanInstance(Object bean, String name) {
        Object object = bean;
        if (bean instanceof FactoryBean) {
            FactoryBean factoryBean = (FactoryBean) bean;
            try {
                if (factoryBean.isSingleton()) {
                    object = this.factoryBeanCache.get(name);
                    if (object == null) {
                        object = factoryBean.getObject();
                        this.factoryBeanCache.put(name, object);
                    }
                } else object = factoryBean.getObject();
            } catch (Exception e) {
                throw new BeansException("Bean [" + name + "], 创建 FactoryBean 加工 Bean 实例失败!", e);
            }
        }
        return object;
    }

    /**
     * 创建 Bean 实例
     *
     * @param beanName       Bean 实例名称
     * @param beanDefinition Bean 定义
     * @return java.lang.Object Bean 实例
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-14 14:52:52
     */
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;

    /**
     * 获取 Bean 定义
     *
     * @param beanName Bean 实例名称
     * @return org.springframework.beas.factory.config.BeanDefinition Bean 定义
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-14 14:53:31
     */
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

    /**
     * 获取所有的 BeanPostProcessor 处理器
     *
     * @return java.util.List<org.springframework.beans.factory.config.BeanPostProcessor> BeanPostProcessor 处理器清单
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-19 21:16:57
     */
    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;
    }

    @Override
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        embeddedValueResolvers.add(valueResolver);
    }

    @Override
    public String resolveEmbeddedValue(String value) {
        String result = value;
        for (StringValueResolver resolver : embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
        }
        return result;
    }

    @Override
    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @Override
    public ConversionService getConversionService() {
        return conversionService;
    }
}

